
package com.yuan.unit;

import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.View.MeasureSpec;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 图片工具类
 * 
 * @author YUAN
 */
public class BitmapHelper {
    public final static String TAG = "BitmapHelper";

    public static Bitmap decodeFile(String filePath) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPurgeable = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        return decodeFile(filePath, options);
    }

    public static Bitmap decodeFile(String filePath, int viewWidth,
            int viewHeight) {
        if (!new File(filePath).exists()) {
            return null;
        }

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options); // 此时返回为空

        options.inSampleSize = getCompressRatio(options.outWidth,
                options.outHeight, viewWidth, viewHeight);
        options.inJustDecodeBounds = false;
        options.inPurgeable = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        Utils.debug(TAG, "decodeFile - width: " + options.outWidth
                + ", height: " + options.outHeight + ", viewWidth: "
                + viewWidth + ", viewHeight: " + viewHeight
                + ", compress ratio: " + options.inSampleSize);

        return decodeFile(filePath, options);
    }

    public static Bitmap decodeFile(String filePath,
            BitmapFactory.Options options) {
        Bitmap bm = null;
        try {
            bm = BitmapFactory.decodeFile(filePath, options);
        } catch (OutOfMemoryError e) {
            System.gc();
            Utils.debug(TAG, "decodeFile: out of memory, causing gc...");

            try {
                bm = BitmapFactory.decodeFile(filePath, options);
            } catch (OutOfMemoryError ie) {
                Utils.debug(TAG, "decodeFile: still no memory after gc...");
                bm = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bm;
    }

    public static Bitmap decodeSampleFromFile(String filePath,
            int compressedRatio) {
        if (!new File(filePath).exists()) {
            return null;
        }

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = compressedRatio;
        options.inPurgeable = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        return decodeFile(filePath, options);
    }

    public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPurgeable = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        return decodeByteArray(data, offset, length, options);
    }

    public static Bitmap decodeByteArrayWithCompressedRatio(byte[] data,
            int offset, int length, int compressRatio) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = compressRatio;
        options.inPurgeable = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        return decodeByteArray(data, offset, length, options);
    }

    public static Bitmap decodeByteArray(byte[] data, int offset, int length,
            int viewWidth, int viewHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(data, offset, length, options); // 此时返回为空

        options.inSampleSize = getCompressRatio(options.outWidth,
                options.outHeight, viewWidth, viewHeight);
        options.inJustDecodeBounds = false;
        options.inPurgeable = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        Utils.debug(TAG, "decodeByteArray - width: " + options.outWidth
                + ", height: " + options.outHeight + ", viewWidth: "
                + viewWidth + ", viewHeight: " + viewHeight
                + ", compress ratio: " + options.inSampleSize);

        return decodeByteArray(data, offset, length, options);
    }

    public static Bitmap decodeByteArray(byte[] data, int offset, int length,
            BitmapFactory.Options options) {
        Bitmap bm = null;
        try {
            bm = BitmapFactory.decodeByteArray(data, offset, length, options);
        } catch (OutOfMemoryError e) {
            System.gc();
            Utils.debug(TAG, "decodeByteArray: out of memory, causing gc...");

            try {
                bm = BitmapFactory.decodeByteArray(data, offset, length,
                        options);
            } catch (OutOfMemoryError ie) {
                Utils.debug(TAG, "decodeByteArray: still no memory after gc...");
                bm = null;
            }
        }

        return bm;
    }

    public static int getCompressRatio(int bWidth, int bHeight, int viewWidth,
            int viewHeight) {
        int compressRatio = 1;
        if (bWidth > 0 && bHeight > 0 && viewWidth > 0 && viewHeight > 0) {
            if (viewWidth * bHeight > bWidth * viewHeight) {
                // 考虑宽边
                compressRatio = (int) ((float) bWidth / viewWidth + 0.2f);
            } else {
                // 考虑高边
                compressRatio = (int) ((float) bHeight / viewHeight + 0.2f);
            }

            compressRatio = Math.max(compressRatio, 1);
        }

        return compressRatio;
    }

    public static Bitmap getCompressedBitmap(String filePath, int widthLimit) {
        return getCompressedBitmap(decodeFile(filePath), widthLimit);
    }

    public static Bitmap getCompressedBitmap(byte[] bytes, int widthLimit) {
        return getCompressedBitmap(decodeByteArray(bytes, 0, bytes.length),
                widthLimit);
    }

    public static Bitmap getCompressedBitmap(Bitmap origin, int widthLimit) {
        if (origin == null) {
            return null;
        }

        int width = origin.getWidth();
        int height = origin.getHeight();
        if (width > widthLimit) {
            height = (int) ((float) height * widthLimit / width + 0.5f);
            width = widthLimit;
        } else {
            return origin;
        }

        Bitmap ret = null;
        try {
            ret = Bitmap.createScaledBitmap(origin, width, height, false);
        } catch (OutOfMemoryError e) {
            System.gc();
            Utils.debug(TAG,
                    "getCompressedBitmap: out of memory, causing gc...");

            try {
                ret = Bitmap.createScaledBitmap(origin, width, height, false);
            } catch (OutOfMemoryError ie) {
                Utils.debug(TAG,
                        "getCompressedBitmap: still not enough memory after gc, returning null ...");
                ret = null;
            }
        }
        return ret;
    }

    public static Bitmap decodeResource(Resources res, int id) {
        Bitmap bm = null;
        BitmapFactory.Options options = new BitmapFactory.Options();
        try {
            bm = BitmapFactory.decodeResource(res, id, options);
        } catch (OutOfMemoryError e) {
            System.gc();
            Utils.debug(TAG, "decodeResource: out of memory, causing gc...");

            try {
                bm = BitmapFactory.decodeResource(res, id, options);
            } catch (OutOfMemoryError ie) {
                Utils.debug(TAG, "decodeResource: still no memory after gc...");
                bm = null;
            }
        }
        return bm;
    }

    public static boolean writeBitmapToFile(Bitmap bitmap, String path,
            int quality) {
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(new File(path));
            bitmap.compress(CompressFormat.JPEG, quality, outputStream);
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
            return false;
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    public static Bitmap createBitmap(int[] colors, int width, int height,
            Bitmap.Config config) {
        Bitmap bm = null;
        try {
            bm = Bitmap.createBitmap(colors, width, height, config);
        } catch (OutOfMemoryError e) {
            System.gc();
            Utils.debug(TAG, "createBitmap: out of memory, causing gc...");

            try {
                bm = Bitmap.createBitmap(colors, width, height, config);
            } catch (OutOfMemoryError ie) {
                Utils.debug(TAG, "createBitmap: still no memory after gc...");
                bm = null;
            }
        }
        return bm;
    }

    public static Bitmap convertViewToBitmap(View view) {
        int bitmapWidth = view.getWidth();
        int bitmapHeight = view.getHeight();
        if (bitmapWidth == 0 || bitmapHeight == 0) {
            view.measure(
                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        } else {
            view.measure(MeasureSpec.makeMeasureSpec(bitmapWidth,
                    MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                    bitmapHeight, MeasureSpec.EXACTLY));
        }
        bitmapWidth = view.getMeasuredWidth();
        bitmapHeight = view.getMeasuredHeight();
        view.layout(0, 0, bitmapWidth, bitmapHeight);
        Bitmap bitmap = null;
        try {
            view.setDrawingCacheEnabled(true);
            view.buildDrawingCache();
            bitmap = view.getDrawingCache();
            return bitmap;
        } catch (OutOfMemoryError ex) {

        }
        return bitmap;
    }

    /**
     * 保存图片为PNG
     * 
     * @param bitmap
     * @param name
     */
    public static void savePNG_After(Bitmap bitmap, String name) {
        File file = new File(name);
        try {
            FileOutputStream out = new FileOutputStream(file);
            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)) {
                out.flush();
                out.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存图片为JPEG
     * 
     * @param bitmap
     * @param path
     */
    public static void saveJPGE_After(Bitmap bitmap, String path) {
        File file = new File(path);
        try {
            FileOutputStream out = new FileOutputStream(file);
            if (bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)) {
                out.flush();
                out.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 使用系统当前日期加以调整作为照片的名称
    @SuppressLint("SimpleDateFormat")
    public static String getPhotoFileName() {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat dateFormat = new SimpleDateFormat(
                "'IMG'_yyyyMMdd_HHmmss");
        return dateFormat.format(date) + ".jpg";
    }
}
